package way.scripts;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.xmlbeans.XmlException;
import way.scripts.classDoc.model.LevelEnum;
import way.scripts.classDoc.model.Table;
import way.scripts.util.XWPFDocumentBuilder;

import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * @author Haozhiqiang  {2021/12/7 13:47}
 */
public class WritingDoc {

    public static void main(String[] args) throws IOException, XmlException {
        String templatePath = "E:\\360MoveData\\Users\\haozhiqiang\\Desktop\\知识图谱构建工具详细设计文档.docx";
        String outPath = "E:\\360MoveData\\Users\\haozhiqiang\\Desktop\\out.docx";


        try (XWPFDocumentBuilder builder = new XWPFDocumentBuilder(templatePath, outPath)) {
            String path = Objects.requireNonNull(WritingDoc.class.getClassLoader().getResource("json.txt")).getPath();
            path = path.replaceFirst("/", "");
            byte[] bytes = Files.readAllBytes(Paths.get(path));
            String str = IOUtils.toString(bytes, "utf8");
            JSONArray list = JSONArray.parseArray(str);

            System.out.println(list);

            for (int i = 0; i < list.size(); i++) {
                JSONObject jsonObject = (JSONObject) list.get(i);

                String level1 = String.valueOf(i + 1);
                // 设置一级标题
                builder.addTitle(level1 + "、 " + jsonObject.getString("name"), LevelEnum.HEADING_1);
                String level2 = level1 + ".";
                builder.addTitle(level2 + "1 模块描述", LevelEnum.HEADING_2);
                builder.addTable(new Table("", "描述", "备注") {{
                    addRow(Arrays.asList("目的", "", ""));
                    addRow(Arrays.asList("功能", "", ""));
                    addRow(Arrays.asList("性能", "", ""));
                }});

                builder.addTitle(level2 + "2 接口列表", LevelEnum.HEADING_2);
                List<Map<String, String>> requestPaths = getInterfaceList(jsonObject);
                Table interfaceTable = new Table("接口名称", "定义", "描述");
                requestPaths.forEach(map -> {
                    interfaceTable.addRow(Arrays.asList(map.get("path"), map.get("name"), map.get("notes")));
                });
                builder.addTable(interfaceTable);


                builder.addTitle(level2 + "3 类列表", LevelEnum.HEADING_2);
                List<String> classList = getClassList(jsonObject);
                Table classListTable = new Table("类名称", "定义", "描述");
                classList.forEach(s -> {
                    classListTable.addRow(Arrays.asList(s, "", ""));
                });
                builder.addTable(classListTable);

                for (int j = 0; j < classList.size(); j ++) {
                    String index = level2 + "3." + (j+1);
                    builder.addTitle(index + " " + classList.get(j), LevelEnum.HEADING_3);
                    List<Map<String, String>> methodList = getNoteClassMethodAndParams(jsonObject, j);
                    Table classTable = new Table("","描述","备注");
                    classTable.addRow("父类","","");
                    classTable.addRow("目的", "","");
                    classTable.addRow("属性", "","");
                    classTable.addRow("方法", "", "");
                    for(Map<String, String> method : methodList) {
                        classTable.addRow("", method.get("method"), method.get("notes"));
                    }
                    builder.addTable(classTable);

                    for (int k = 0; k < methodList.size(); k++) {
                        String methodIndex = index + "." + (k+1);
                        Map<String, String> method = methodList.get(k);
                        builder.addTitle(methodIndex + " " + method.get("method"), LevelEnum.HEADING_4);
                        Table methodTable = new Table("", "类型", "约束/说明");
                        methodTable.addRow("输入", method.get("params"), "");
                        methodTable.addRow("输出", method.get("return"), "");
                        builder.addTable(methodTable);
                    }
                }

            }

        }
    }

    public static String get(Pattern pattern, String text) {
        Matcher matcher = pattern.matcher(text);
        if (matcher.find()) {
            return matcher.group(1);
        }
        return "";
    }

    private static final Pattern apiPattern = Pattern.compile("@Api\\(value\\s*=\\s*\"(.*?)\"");
    private static final Pattern requestPathPattern = Pattern.compile("@RequestMapping\\(value\\s*=\\s*\"(.*?)\"");
    private static final Pattern apiName = Pattern.compile("@ApiOperation\\(value\\s*=\\s*\"(.*?)\"");
    private static final Pattern apiNotes = Pattern.compile("@ApiOperation\\([\\s\\S]*notes\\s*=\\s*\"(.*?)\"");
    private static final String targetFileDir = "D:\\work\\code\\cks-tools";

    public static List<Map<String, String>> getInterfaceList(JSONObject jsonObject) throws IOException {
        List<Map<String, String>> requestPaths = new ArrayList<>();
        JSONArray interfaces = jsonObject.getJSONArray("interface_class");
        for (Object o : interfaces) {
            String ic = String.valueOf(o);
            String path = String.join("\\\\", ic.split("\\."));
            Iterator<String> iterator = Files.lines(Paths.get(targetFileDir + "\\" + jsonObject.getString("module") + "\\src\\main\\java\\" + path + ".java")).iterator();

            String apiPath = "";
            while (iterator.hasNext()) {
                String l = iterator.next();
                Matcher matcher = apiPattern.matcher(l);
                if (matcher.find()) {
                    apiPath = matcher.group(1);
                    break;
                }
            }


            Map<String, String> apiMap = null;
            while (iterator.hasNext()) {
                String l = iterator.next();

                String p = get(requestPathPattern, l);
                if (StringUtils.isNotEmpty(p)) {
                    apiMap = new HashMap<>();
                    apiMap.put("path", apiPath + p);
                    continue;
                }

                if (apiMap == null) {
                    continue;
                }
                String name = get(apiName, l);
                if (StringUtils.isNotEmpty(name)) {
                    apiMap.put("name", name);
                    apiMap.put("notes", get(apiNotes, l));

                    Map<String, String> tmp = apiMap;
                    requestPaths.add(tmp);
                    apiMap = null;
                }
            }
        }
        return requestPaths;
    }

    public static List<String> getClassList(JSONObject jsonObject) {
        List<String> list = new ArrayList<>();
        JSONArray classlist = jsonObject.getJSONArray("class");
        for (Object o : classlist) {
            String ic = String.valueOf(o);
            String[] strs = ic.split("\\.");
            list.add(strs[strs.length-1]);
        }
        return list;
    }

    private static final Pattern notesPattern = Pattern.compile("\\*\\s*(.*?)\\s*");
    private static final Pattern methodPattern = Pattern.compile("\\s+\\w+<*\\w*>*\\s+(.*?)\\(");
    private static final Pattern paramsPattern = Pattern.compile("\\s+\\w+<*\\w*>*\\s+\\w+\\((.*?)\\)");
    private static final Pattern returnPattern = Pattern.compile("@return\\s+(.*?)");


    public static List<Map<String, String>> getNoteClassMethodAndParams(JSONObject jsonObject, int classIndex) throws IOException {
        String classPath = String.valueOf(jsonObject.getJSONArray("class").get(classIndex));
        String path = String.join("\\\\", classPath.split("\\."));
        Iterator<String> iterator = Files.lines(Paths.get(targetFileDir + "\\" + jsonObject.getString("module") + "\\src\\main\\java\\" + path + ".java")).iterator();
        List<Map<String, String>> resultList = new ArrayList<>();
        Map<String, String> map = null;

        while (iterator.hasNext()) {
            String l = iterator.next();

            if (l.trim().equals("/**")) {
                map = new HashMap<>();
                continue;
            }

            String returnStr = null;
            if (l.contains("@return")) {
                returnStr = l.replaceFirst("\\*", "").replaceFirst("@return", "").trim();
            }

            if (l.trim().contains("*") && StringUtils.isNotEmpty(returnStr)) {
                if (map == null) {
                    map = new HashMap<>();
                    map.put("notes", "");
                }
                map.put("return", returnStr);
                continue;
            }

            String methodName = get(methodPattern, l);
            String params = "";
            if (!l.contains("\\*") && !l.contains("\\\\") && StringUtils.isNotEmpty(methodName)) {
                String newReturn = l.trim().split(" ")[0];
                if (map == null) {
                    map = new HashMap<>();
                    map.put("notes", "");

                }
                if (StringUtils.isEmpty(map.get("return"))) {
                    map.put("return", newReturn);
                }

                params = get(paramsPattern, l);
                map.put("method", methodName);
                map.put("params", params);

                Map<String, String> temp = map;
                resultList.add(temp);
                map = null;
                continue;
            }

            if (map == null) {
                continue;
            }

            if (map.size() == 0 && l.contains("*")) {
                map.put("notes", l.replaceFirst("\\*", "").trim());
            }
        }
        return resultList;
    }

    public static Map<String, Map<String, String>> getClas1sList(JSONObject jsonObject) throws IOException {
return null;
    }

}
